/*
 * The RavenX Library
 * Copyright (c) 2008 by Solidus
 * 
 * Permission to use, copy, modify, distribute and sell this software
 * and its documentation for any purpose is hereby granted without fee,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear
 * in supporting documentation.It is provided "as is" without express 
 * or implied warranty.
 *
 */

#include "rx_queue.h"
#include "rx_vector.h"
#include "rx_list.h"
#include "rx_algo.h"
#include "rx_debug.h"
#include "rx_mem.h"

RX_SPACE_BEG


typedef struct __rx_queue_tag rx_queue_t;


rx_queue_t* rx_queue_create(const rx_info_t *info, const rx_alloc_t *palloc)
{
		return (rx_queue_t*)rx_list_create(info, palloc);
}

void rx_queue_destroy(rx_queue_t *self)
{
		if(self != NULL)rx_list_destroy((rx_list_t*)self);
}


void* rx_queue_front(rx_queue_t *self)
{
		RX_ASSERT(!rx_list_is_empty((rx_list_t*)self));
		return rx_list_node_data(rx_list_head((rx_list_t*)self));
}

void* rx_queue_back(rx_queue_t *self)
{
		RX_ASSERT(!rx_list_is_empty((rx_list_t*)self));
		return rx_list_node_data(rx_list_tail((rx_list_t*)self));
}


void  rx_queue_push(rx_queue_t *self, const void *data)
{
		rx_list_push_back((rx_list_t*)self, data);

}

void  rx_queue_pop(rx_queue_t *self)
{
		if(rx_list_is_empty((rx_list_t*)self))return;
		rx_list_pop_front((rx_list_t*)self);
}

size_t rx_queue_size(const rx_queue_t *self)
{
		return rx_list_size((rx_list_t*)self);
}

rx_bool rx_queue_is_empty(const rx_queue_t *self)
{
		return rx_queue_size(self) == 0 ? rx_true : rx_false;

}











/**************************************************************************rx_prio_queue_t***************************************************************/






/*
typedef struct __rx_prio_queue_tag 
{
		rx_vector_t		*container;

		rx_cmp_func_t	cmp_f;
		rx_swap_func_t  swap_f;
		size_t			elem_size;
		rx_alloc_t		alloc;
		
}rx_prio_queue_t;*/



rx_prio_queue_t* rx_prio_queue_create(const rx_info_t *info, const rx_alloc_t *palloc)
{
		return (rx_prio_queue_t*)rx_vector_create(info, palloc);
}


void rx_prio_queue_destroy(rx_prio_queue_t* self)
{
		if(self != NULL)
		{
				rx_vector_destroy((rx_vector_t*)self);
		}

}


void  rx_prio_queue_push(rx_prio_queue_t *self, const void *data)
{
		const rx_info_t *info;
		rx_vector_push_back((rx_vector_t*)self, data);
		
		if(rx_vector_size((rx_vector_t*)self) == 1)return;
		info = rx_vector_info((rx_vector_t*)self);
		RX_ASSERT(info->cmp_f != NULL && info->swap_f != NULL);
		rx_push_heap(rx_vector_begin((rx_vector_t*)self), rx_vector_size((rx_vector_t*)self), info->elem_size, info->cmp_f, info->swap_f);
}



RavenAPI void  rx_prio_queue_pop(rx_prio_queue_t *self)
{
		size_t size; const rx_info_t *info;
		

		size = rx_vector_size((rx_vector_t*)self);
		info = rx_vector_info((rx_vector_t*)self);

		if(size == 0)return;
		if(size > 1)rx_pop_heap(rx_vector_begin((rx_vector_t*)self), rx_vector_size((rx_vector_t*)self), info->elem_size, info->cmp_f, info->swap_f);

		rx_vector_pop_back((rx_vector_t*)self);

}


const void* rx_prio_queue_top(const rx_prio_queue_t *self)
{
		RX_ASSERT(!rx_prio_queue_is_empty(self));
		return rx_vector_begin((rx_vector_t*)self);
}

size_t rx_prio_queue_size(const rx_prio_queue_t *self)
{
		return rx_vector_size((rx_vector_t*)self);

}

rx_bool rx_prio_queue_is_empty(const rx_prio_queue_t *self)
{
		return rx_prio_queue_size(self) == 0;

}

/**/
#if(0)

static RX_INLINE rx_bool __prio_is_valid(const rx_prio_queue_t *self)
{
		if(self == NULL || self->container == NULL || self->elem_size == 0 || self->alloc.alloc_f == NULL || self->alloc.dealloc_f == NULL) return rx_false;
		if(self->cmp_f == NULL || self->swap_f == NULL)return rx_false;

		return rx_true;
}

rx_prio_queue_t* rx_prio_queue_create(size_t element_size, rx_init_func_t init_f, rx_copy_func_t copy_f, rx_uninit_func_t uninit_f, const rx_alloc_t *palloc, rx_cmp_func_t cmp_f, rx_swap_func_t swap_f)
{
		rx_prio_queue_t *res;

		if(palloc == NULL)palloc = rx_mem_default_alloctor();

		RX_ASSERT(palloc != NULL && palloc->alloc_f != NULL && palloc->dealloc_f != NULL);
		RX_ASSERT(cmp_f != NULL && swap_f != NULL);

		res = (rx_prio_queue_t*)palloc->alloc_f(sizeof(rx_prio_queue_t), palloc->ctx);
		res->alloc = *palloc;

		RX_FATAL_ERROR(res != NULL);
		
		
		res->container = rx_vector_create(element_size, init_f, copy_f, uninit_f, palloc);
		res->cmp_f = cmp_f;
		res->swap_f = swap_f;
		res->elem_size = element_size;
		return res;
}

void rx_prio_queue_destroy(rx_prio_queue_t* self)
{
		if(self != NULL)
		{
				RX_ASSERT(__prio_is_valid(self));
				rx_vector_destroy(self->container);
				self->alloc.dealloc_f(self,  self->alloc.ctx);
		}
}


void  rx_prio_queue_push(rx_prio_queue_t *self, const void *data)
{
		RX_ASSERT(__prio_is_valid(self));

		rx_vector_push_back(self->container, data);
		
		if(rx_prio_queue_size(self) == 1)return;
		
		rx_push_heap(rx_vector_begin(self->container), rx_vector_size(self->container), self->elem_size, self->cmp_f, self->swap_f);

}

void  rx_prio_queue_pop(rx_prio_queue_t *self)
{
		size_t size;
		RX_ASSERT(__prio_is_valid(self));

		size = rx_prio_queue_size(self);

		if(size == 0)return;
		if(size > 1)rx_pop_heap(rx_vector_begin(self->container), rx_vector_size(self->container), self->elem_size, self->cmp_f, self->swap_f);

		rx_vector_pop_back(self->container);
}


const void* rx_prio_queue_top(const rx_prio_queue_t *self)
{
		RX_ASSERT(__prio_is_valid(self));
		RX_ASSERT(!rx_prio_queue_is_empty(self));
		return rx_vector_begin(self->container);
}



rx_bool rx_prio_queue_is_empty(const rx_prio_queue_t *self)
{
		return (rx_prio_queue_size(self) == 0 ? rx_true : rx_false);
}


size_t rx_prio_queue_size(const rx_prio_queue_t *self)
{
		RX_ASSERT(__prio_is_valid(self));
		return rx_vector_size(self->container);
}

#endif










RX_SPACE_END
